package io.renren.wh.order.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.renren.common.utils.PageUtils;
import io.renren.common.utils.Query;
import io.renren.common.utils.RedisUtils;
import io.renren.modules.job.entity.ScheduleJobEntity;
import io.renren.modules.job.service.ScheduleJobService;
import io.renren.modules.job.utils.ScheduleUtils;
import io.renren.wh.channel.entity.ChannelConfigEntity;
import io.renren.wh.channel.entity.ChannelInfoEntity;
import io.renren.wh.channel.service.ChannelConfigService;
import io.renren.wh.channel.service.ChannelInfoService;
import io.renren.wh.common.Constant;
import io.renren.wh.interfaces.service.InterfacesService;
import io.renren.wh.merchant.entity.InfoEntity;
import io.renren.wh.merchant.entity.MerchantKeyEntity;
import io.renren.wh.merchant.entity.RateEntity;
import io.renren.wh.merchant.service.InfoService;
import io.renren.wh.merchant.service.MerchantKeyService;
import io.renren.wh.merchant.service.RateService;
import io.renren.wh.order.dao.OrderInfoDao;
import io.renren.wh.order.entity.OrderInfoEntity;
import io.renren.wh.order.enums.CallBackStatusEnum;
import io.renren.wh.order.enums.OrderStatusEnum;
import io.renren.wh.order.enums.ReCallBackStatusEnum;
import io.renren.wh.order.service.OrderInfoService;
import io.renren.wh.order.util.GroovyUtil;
import io.renren.wh.order.util.MySignUtil;
import io.renren.wh.order.util.ResponseInfoUtil;
import io.renren.wh.order.vo.PayVo;
import org.apache.commons.lang.StringUtils;
import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.script.Invocable;
import javax.script.ScriptException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;


@Service("orderInfoService")
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoDao, OrderInfoEntity> implements OrderInfoService {

    @Autowired
    private Scheduler scheduler;

    @Autowired
    private InfoService infoService;

    @Autowired
    private InterfacesService interfacesService;

    @Autowired
    private ChannelInfoService channelInfoService;

    @Autowired
    private ScheduleJobService scheduleJobService;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private MerchantKeyService merchantKeyService;

    @Autowired
    private RateService rateService;

    @Autowired
    private ChannelConfigService channelConfigService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {

        QueryWrapper queryWrapper = new QueryWrapper<OrderInfoEntity>();
        if (params.get("interfaceid") != null){
            queryWrapper.eq("interfaceid",params.get("interfaceid"));
        }
        if (params.get("merchantname") != null && StringUtils.isNotBlank(params.get("merchantname").toString())){
            queryWrapper.like("merchantname",params.get("merchantname"));
        }
        if (params.get("channelname") != null && StringUtils.isNotBlank(params.get("channelname").toString())){
            queryWrapper.like("channelname",params.get("channelname"));
        }
        if (params.get("merchantordersn") != null && StringUtils.isNotBlank(params.get("merchantordersn").toString())){
            queryWrapper.eq("merchantordersn",params.get("merchantordersn"));
        }
        if (params.get("systemordersn") != null && StringUtils.isNotBlank(params.get("systemordersn").toString())){
            queryWrapper.eq("systemordersn",params.get("systemordersn"));
        }
        if (params.get("orderstatus") != null){
            queryWrapper.eq("orderstatus",params.get("orderstatus"));
        }

        if (params.get("starttime") != null && StringUtils.isNotBlank(params.get("starttime").toString())){

            queryWrapper.ge("starttime",params.get("starttime"));
        }

        if (params.get("endtime") != null && StringUtils.isNotBlank(params.get("endtime").toString())){
            queryWrapper.le("endtime",params.get("endtime").toString()+" 23:59:59");
        }

        if (params.get("callbackStatus") != null){
            queryWrapper.eq("callbackStatus",params.get("callbackStatus"));
        }

        if (params.get("merchantId") != null){
            queryWrapper.eq("merchantId",params.get("merchantId"));
        }

        //排序
        queryWrapper.orderByDesc("startTime");

        IPage<OrderInfoEntity> page = this.page(
                new Query<OrderInfoEntity>().getPage(params),
                queryWrapper
        );

        // List<MerchantOrderVo> merchantOrderVos = new ArrayList<>();
        // for (OrderInfoEntity orderInfo : page.getRecords()) {
        //     MerchantOrderVo merchantOrderVo = new MerchantOrderVo();
        //     BeanUtils.copyProperties(orderInfo,merchantOrderVo);
        //     merchantOrderVos.add(merchantOrderVo);
        // }

        // page.setRecords(merchantOrderVos)

        return new PageUtils(page);
    }

    /**
     * 创建订单
     * @param payVo
     * @return
     */
    @Transactional
    @Override
    public ResponseInfoUtil createOrderInfo(PayVo payVo) throws RuntimeException {

        // 通过APPID获取MerchantKey对象
        MerchantKeyEntity merchantKey = merchantKeyService.queryByeAppId(payVo.getAppId());

        if (null == merchantKey){
            throw new RuntimeException("APPID无效");
        }

        //验证sign
        String sign =MySignUtil.getSign(payVo.getOrderNo(),payVo.getAmount(),payVo.getPayType(),merchantKey.getSecretkey());
        if (null == sign || !sign.equals(payVo.getSign())){
            throw new RuntimeException("Sign无效");
        }

        merchantKey.setNotifyUrl(payVo.getNotifyUrl());

        //检查商户状态是否可用
        InfoEntity merchantInfo = infoService.getById(merchantKey.getMerchantid());
        if (merchantInfo.getStatus()!=0){
            throw new RuntimeException("商户未启用");
        }

        //检查该商户是否存在相应的费率信息（是否有对应的接口）
        RateEntity merchantRate = rateService.queryByMerchantidAndInterfacecode(merchantKey.getMerchantid(),payVo.getPayType());
        if (merchantRate == null){
            throw new RuntimeException("商户未配置费率");
        }

        // 选择通道
        //获得当前商户费率有哪些通道
        List<Integer> listChannelId = rateService.queryChannelByRateId(merchantRate.getId());

        if (listChannelId == null || listChannelId.size()==0){
            throw new RuntimeException("商户未配置通道");
        }

        List<Integer> listEnableChannelIds = new ArrayList<>();
        //检查通道状态
        for (int i=0;i<listChannelId.size();i++){
            ChannelInfoEntity channelInfo = channelInfoService.getById(listChannelId.get(i));
            if (channelInfo.getStatus()==0){
                listEnableChannelIds.add(listChannelId.get(i));
            }
        }

        if (listEnableChannelIds.size()==0){
            throw new RuntimeException("商户没有可用的通道");
        }

        Integer channelId = listEnableChannelIds.get(0);
        //如果有很多通道，则随机选一个通道
        if (listEnableChannelIds.size()>1){
            int index = RandomUtil.randomInt(listEnableChannelIds.size());
            channelId = listEnableChannelIds.get(index);
        }

        ChannelInfoEntity channelInfo = channelInfoService.getById(channelId);
        if (channelInfo == null){
            throw new RuntimeException("不存在通道："+channelId);
        }

        //获取通道配置
        ChannelConfigEntity channelConfig =channelConfigService.queryByChannleId(channelId);

        //适配通道的请求
        if (channelConfig == null || StringUtils.isEmpty(channelConfig.getScript())) {
            throw new RuntimeException("没有通道配置");
        }
        //加载脚本
        Invocable inv = null;
        try {
            inv = GroovyUtil.getInvocable(channelConfig.getScript());
        } catch (ScriptException e) {
            e.printStackTrace();
            throw new RuntimeException("通道配置有误");
        }

        /**
         * 新增订单记录
         */
        OrderInfoEntity orderInfo = new OrderInfoEntity();
        //设置商户相关信息
        orderInfo.setMerchantid(merchantRate.getMerchantid());
        orderInfo.setMerchantname(merchantRate.getMerchantname());
        orderInfo.setMerchantrate(merchantRate.getRate());
        orderInfo.setMerchantordersn(payVo.getOrderNo());
        //设置通道相关信息
        orderInfo.setChannelid(channelInfo.getId());
        orderInfo.setChannelname(channelInfo.getChannelname());
        orderInfo.setChannelrate(channelInfo.getChannelrate());
        //设置接口相关信息
        orderInfo.setInterfaceid(channelInfo.getInterfaceid());
        orderInfo.setInterfacecode(channelInfo.getInterfacecode());
        orderInfo.setInterfacename(channelInfo.getInterfacename());

        //生成随机数系统订单号
        orderInfo.setSystemordersn(RandomUtil.simpleUUID());
        orderInfo.setOrderaccount(payVo.getAmount());
        orderInfo.setIssdk(payVo.getIsSdk());
        Date currDate = new Date();
        orderInfo.setOrdertime(currDate);
        orderInfo.setStarttime(currDate);
        orderInfo.setOrderstatus(OrderStatusEnum.NO.type);
        orderInfo.setCallbackstatus(CallBackStatusEnum.NO.type);
        orderInfo.setRecallbackstatus(ReCallBackStatusEnum.NO.type);

        this.save(orderInfo);
        //将系统订单号存入redis
        redisUtils.set(Constant.ORDER_PREFIX+orderInfo.getSystemordersn(),redisUtils.toJson(orderInfo));
        //将channelConfig缓存起来
        redisUtils.set(Constant.CHANNEL_CONFIG+orderInfo.getSystemordersn(),redisUtils.toJson(channelConfig));
        //将商户key缓存起来
        redisUtils.set(Constant.MERCHANT_KEY+orderInfo.getSystemordersn(),redisUtils.toJson(merchantKey));

        String responseStr = "";
        try {
            //适配当前通道的请求参数，并发送支付请求
            responseStr = (String) inv.invokeFunction("orderPay", orderInfo,channelConfig);
        } catch (Exception e) {
            e.printStackTrace();
            redisUtils.delete(Constant.ORDER_PREFIX+orderInfo.getSystemordersn());
            redisUtils.delete(Constant.CHANNEL_CONFIG+orderInfo.getSystemordersn());
            redisUtils.delete(Constant.MERCHANT_KEY+orderInfo.getSystemordersn());
            throw new RuntimeException("请求下单失败，通道配置有误");
        }

        //适配响应内容
        ResponseInfoUtil responseInfoUtil = null;
        try {
            responseInfoUtil = (ResponseInfoUtil) inv.invokeFunction("getResponseInfo", responseStr);
            boolean respIsSuccess = (boolean) responseInfoUtil.getData().get("success");
            if (!respIsSuccess){
                throw new RuntimeException("请求下单失败，请检查通道");
            }
            responseInfoUtil.getData().put("orderNo",orderInfo.getMerchantordersn());
            return responseInfoUtil;
        } catch (ScriptException e) {
            e.printStackTrace();
            redisUtils.delete(Constant.ORDER_PREFIX+orderInfo.getSystemordersn());
            redisUtils.delete(Constant.CHANNEL_CONFIG+orderInfo.getSystemordersn());
            redisUtils.delete(Constant.MERCHANT_KEY+orderInfo.getSystemordersn());
            throw new RuntimeException("通道配置有误");
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
            redisUtils.delete(Constant.ORDER_PREFIX+orderInfo.getSystemordersn());
            redisUtils.delete(Constant.CHANNEL_CONFIG+orderInfo.getSystemordersn());
            redisUtils.delete(Constant.MERCHANT_KEY+orderInfo.getSystemordersn());
            throw new RuntimeException("通道响应配置有误");
        }
    }

    @Transactional
    @Override
    public void orderSuccess(OrderInfoEntity orderInfo) {

        //修改订单状态
        UpdateWrapper<OrderInfoEntity> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set("orderstatus",orderInfo.getOrderstatus());
        updateWrapper.eq("id",orderInfo.getId());

        this.update(updateWrapper);

        //修改redis中的订单
        redisUtils.set(Constant.ORDER_PREFIX+orderInfo.getSystemordersn(),orderInfo);

        //删除redis中对应订单的数据
        redisUtils.delete(Constant.CHANNEL_CONFIG+orderInfo.getSystemordersn());
    }

    @Transactional
    @Override
    public void orderCallbackSuccess(OrderInfoEntity orderInfo) {
        //修改订单状态
        UpdateWrapper<OrderInfoEntity> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set("callbackstatus",orderInfo.getCallbackstatus());
        updateWrapper.set("recallbackstatus",orderInfo.getRecallbackstatus());
        updateWrapper.set("endtime",orderInfo.getEndtime());
        updateWrapper.eq("id",orderInfo.getId());

        this.update(updateWrapper);

        //删除redis中对应订单的数据
        redisUtils.delete(Constant.ORDER_PREFIX+orderInfo.getSystemordersn());
        redisUtils.delete(Constant.MERCHANT_KEY+orderInfo.getSystemordersn());

    }

    @Transactional
    @Override
    public void createCallBackTask(OrderInfoEntity orderInfo) {

        //如果商户状态为停用，则不做处理
        InfoEntity merchantInfo = infoService.getById(orderInfo.getMerchantid());
        if (merchantInfo == null || merchantInfo.getStatus()==1){
            return;
        }

        ScheduleJobEntity scheduleJob = new ScheduleJobEntity();
        scheduleJob.setParams(orderInfo.getSystemordersn());
        scheduleJob.setBeanName("callBackMerchantTask");
        scheduleJob.setCronExpression("0/1 * * * * ?");
        scheduleJob.setCreateTime(new Date());
        scheduleJob.setStatus(io.renren.common.utils.Constant.ScheduleStatus.NORMAL.getValue());
        scheduleJobService.save(scheduleJob);

        //将定时任务存入redis
        redisUtils.set(Constant.CALLBACK_PREFIX+orderInfo.getSystemordersn(),redisUtils.toJson(scheduleJob));
        ScheduleUtils.createScheduleJob(scheduler, scheduleJob);
    }

}